*-------------------------------------------------------------------------------
* Price and Wasserman (2024), "The Summer Drop in Female Employment"
*
* Description: Save a nicely specified Stata graph in .pdf format.
*-------------------------------------------------------------------------------

capture program drop nicepdf
program define nicepdf
	version 15.0
	syntax anything(name=outputfile id="output filename"), ///
	[                       ///
		style(string)       /// graph style: "paper" or "slides" (default: paper)
		panels(integer 1)   /// number of panels (default: 1)
		scale(real -1)      /// scaling factor (default: based on style/panels)
		xsize(real -1)		/// graph size in x-dimension
		ysize(real -1)		/// graph size in y-dimension
		indirect            /// export as an .eps tempfile, then convert to .pdf
		nocrop              /// suppress automatic cropping of output file
		cropbuffer(real 2)  /// leave a whitespace "buffer" when cropping
		replace             /// overwrite output file if it exists
	]


	* Parse arguments and options
	*---------------------------------------------------------------------------

	* Remove external quotes
	gettoken outputfile : outputfile

	* Verify that the user has supplied a valid output file name
	if "`replace'" == "" {
		* replace on => output file must be valid, openable, and nonexistent
		confirm new file "`outputfile'"
	}
	else {
		* replace off => output file must be valid, openable, but may exist
		capture confirm new file "`outputfile'"
		if _rc != 0 & _rc != 602 {
			confirm file "`outputfile'"
		}
	}

	* Possible styles: paper, slides, or unspecified
	if !inlist("`style'", "paper", "slides", "") {
		display as error `"nicepdf.ado error: option "style" must be either "paper" or "slides""'
		exit = 9
	}

	* Verify that user has supplied a valid scaling factor, if any
	if `scale' <= 0 & `scale' != -1 {
		display as error `"nicepdf.ado error: option "scale()" requires a positive real number"'
		exit = 9
	}

	* Specify graph size
	foreach g in "x" "y" {
		if ``g'size' <= 0 & ``g'size' != -1 {
			display as error `"nicepdf.ado error: option "`g'size()" requires a positive real number"'
			exit = 9
		}

		if ``g'size' > 0 {
			local `g'size "`g'size(``g'size')"
		}
		else {
			local `g'size
		}
	}


	* Handle schemes
	*---------------------------------------------------------------------------

	* Treat currently specified scheme as the "base" scheme for 1-panel figures
	local base_scheme `=c(scheme)'

	* Specify the appropriate scheme
	if `panels' < 1 {
		display as error "nicepdf.ado error: number of panels must be a positive integer"
		exit = 9
	}
	else if `panels' == 1 {
		local scheme "`base_scheme'"
	}
	else {
		local scheme "`base_scheme'_`panels'panel"
	}

	* Verify that the requisite scheme is available
	capture which `scheme'.scheme
	if _rc {
		display as error `"nicepdf.ado error: scheme `scheme' not found along adopath"'
		exit = 9
	}


	* Handle fonts
	*---------------------------------------------------------------------------

	* Check whether a font directory has been declared
	if "$fontdir" != "" {
		* Specify font directory
		local fontdir `"fontdir("$fontdir")"'

		* Serif font: CMU Serif if installed, default font otherwise
		capture {
			confirm file "$fontdir/cmunrm.ttf"
			confirm file "$fontdir/cmunit.ttf"
			confirm file "$fontdir/cmunbx.ttf"
			confirm file "$fontdir/cmunbi.ttf"
		}
		if _rc == 0 {
			local fontfaceserif `"fontfaceserif("CMU Serif")"'
		}

		* Sans serif font: CMU Sans Serif if installed, default font otherwise
		capture {
			confirm file "$fontdir/cmunss.ttf"
			confirm file "$fontdir/cmunsi.ttf"
			confirm file "$fontdir/cmunsx.ttf"
			confirm file "$fontdir/cmunso.ttf"
		}
		if _rc == 0 {
			local fontfacesans `"fontfacesans("CMU Sans Serif")"'
		}

		* Monospaced font: CMU Typewriter if installed, default font otherwise
		capture {
			confirm file "$fontdir/cmuntt.ttf"
			confirm file "$fontdir/cmunti.ttf"
			confirm file "$fontdir/cmuntb.ttf"
			confirm file "$fontdir/cmuntx.ttf"
		}
		if _rc == 0 {
			local fontfacemono `"fontfacemono("CMU Typewriter Text")"'
		}
	}
	else {
		* If font directory unknown, leave fonts unspecified
		local fontdir
		local fontfaceserif
		local fontfacesans
		local fontfacemono
	}


	* Optimize fonts and scalings either for papers or for slides
	*---------------------------------------------------------------------------

	* If style unspecified, default to paper style
	if "`style'" == "paper" | "`style'" == "" {
		* Default font: serif
		if regexm(`"`fontfaceserif'"', "CMU Serif") {
			local fontface `"fontface("CMU Serif")"'
		}
		else {
			local fontface
		}

		* Default scaling: 100% for one panel, inflate for more panels
		if `scale' == -1 {
			if `panels' == 1 local scale 1.10
			if `panels' == 2 local scale 1.25
			if `panels' >= 3 local scale 1.30
		}
	}
	else if "`style'" == "slides" {
		* Default font: sans serif
		if regexm(`"`fontfacesans'"', "CMU Sans Serif") {
			local fontface `"fontface("CMU Sans Serif")"'
		}
		else {
			local fontface
		}

		* Default scaling: >100% for one panel, inflate for more panels
		if `scale' == -1 {
			if `panels' == 1 local scale 1.10
			if `panels' == 2 local scale 1.15
			if `panels' >= 3 local scale 1.25
		}
	}

	*---------------------------------------------------------------------------
	* Write graph to disk. Most of the time, direct export to .pdf works fine,
	* but for reasons that aren't clear, Stata sometimes throws error 691
	* ("unable to save PDF file"). To circumvent this problem, the option
	* "indirect" instructs Stata to first export to .eps, then convert to .pdf.
	*---------------------------------------------------------------------------

	* Rescale figure and use scheme optimized for desired number of panels
	graph display, scale(`scale') scheme(`scheme') `xsize' `ysize'

	* Skip font specification for GUI users
	if "`c(console)'" == "" {
		local fontdir
		local fontface
		local fontfaceserif
		local fontfacesans
		local fontfacemono
	}

	* Export to .pdf: directly or indirectly
	tempfile eps pdf
	if "`indirect'" == "" {
		capture graph export `pdf', ///
			as(pdf)             ///
			`fontdir'           ///
			`fontface'          ///
			`fontfaceserif'     ///
			`fontfacesans'      ///
			`fontfacemono'
		if _rc == 691 {
			display as error `"nicepdf.ado error: Stata threw error 691 ("unable to save PDF file"). To circumvent this issue, try rerunning nicepdf with the option "indirect" enabled."'
			exit = 9
		}
	}
	else {
		graph export `eps', ///
			as(eps)             ///
			`fontdir'           ///
			`fontface'          ///
			`fontfaceserif'     ///
			`fontfacesans'      ///
			`fontfacemono'

		shell epstopdf --outfile="`pdf'" "`eps'"
	}

	* Unless instructed otherwise, crop the .pdf
	if "`crop'" == "" {
		shell pdfcrop `pdf' `pdf' --margins `cropbuffer'
	}

	* Save the output file to the output directory
	copy `pdf' "`outputfile'", `replace'
end
